package pl.polsl.mmm.projectcomm.util;

import static android.opengl.GLES20.*;
import android.util.Log;

public class ShaderHelper {
	private static final String TAG = "ShaderHelper";
	
	public static int compileVertexShader( String shaderCode ) {
		return compileShader(GL_VERTEX_SHADER, shaderCode);
	}
	
	public static int compileFragmentShader ( String shaderCode) {
		return compileShader(GL_FRAGMENT_SHADER, shaderCode);
	}
	
	private static int compileShader( int type , String shaderCode ) {
		//pobranie identyfikatora dla danego typu shadera z api openGLa
		final int shaderObjectId = glCreateShader(type);
		//bufor na informacje o rezultacie kompilacji w api openGL
		final int[] compileStatus = new int[1];
		//nie pykło zapytanie api...
		if(shaderObjectId == 0) {
			if (LoggerConfig.ON) {
				Log.w(TAG, "Could not create new shader.");
			}
			return 0;
		}
		//wskazanie kodu źródłowego shadera
		glShaderSource(shaderObjectId, shaderCode);
		//wywołanie kompilacji
		glCompileShader(shaderObjectId);
		//pobranie rezultatu (statusu)
		glGetShaderiv(shaderObjectId, GL_COMPILE_STATUS, compileStatus, 0);
		//zalogowanie o pomylsnej kompilacji
		if(LoggerConfig.ON) {
			Log.v(TAG, "Results of compiling source:" + "\n" + shaderCode + "\n" + glGetShaderInfoLog(shaderObjectId));
		}
		//jesli kompilacja nie wyszla 
		if(compileStatus[0] == 0) {
			//kasowanie obiektu shadera w API !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ważne
			glDeleteShader(shaderObjectId);
			//logowanie tego faktu
			if(LoggerConfig.ON) {
				Log.w(TAG, "Compilation of shader failed!");
			}
			return 0;
		}
		//zwrócenie id obiektu skompilowanego shadera
		return shaderObjectId;
	}
	//metoda do powiazania ze soba fragment i vertex shaderów
	public static int linkProgram(int vertexShaderId, int fragmentShaderId) {
		//uzyskanie id programu ( polaczenia shader�w ) od api openGL
		final int programObjectId = glCreateProgram();
		//bufor na status powiazania shaderów
		final int[] linkStatus = new int[1];
		//coś nie pykło przy zdobywaniu id programu
		if ( programObjectId == 0) {
			if (LoggerConfig.ON) {
				Log.w(TAG, "Could not create new program");
			}
			return 0;
		}
		//dolaczanie shadera do programu
		glAttachShader(programObjectId, vertexShaderId);
		glAttachShader(programObjectId, fragmentShaderId);
		//powiazanie dodanych shaderow
		glLinkProgram(programObjectId);
		//pobranie statusu operacji
		glGetProgramiv(programObjectId, GL_LINK_STATUS, linkStatus, 0);
		//logowanie wyniku operacji
		if (LoggerConfig.ON) {
			Log.v(TAG, "Results of linking program:\n" + glGetProgramInfoLog(programObjectId));
		}
		//jesli sie nie powiodlo...
		if (linkStatus[0] == 0) {
			//kasowanie obiektu programu w api!!!!!!!!!!!!!!!!!!!!!!!!!!
			glDeleteProgram(programObjectId);
			if (LoggerConfig.ON) {
				Log.w(TAG, "Linking of program failed.");			
			}
			return 0;
		}
		//zwracanie identyfikatora programu ( połączenia obu shaderów )
		return programObjectId;	
	}
	//sprawdzenie poprawnosci zlaczonego programu ( złożonego z dwóch shaderów ) w api OpenGLa
	public static boolean validateProgram(int programObjectId) {
		glValidateProgram(programObjectId);
		
		final int[] validateStatus = new int[1];
		glGetProgramiv(programObjectId, GL_VALIDATE_STATUS, validateStatus, 0);
		Log.v(TAG, "Results of validating program: " + validateStatus[0] + "\nLog:"
				+ glGetProgramInfoLog(programObjectId));
		
		return validateStatus[0] != 0;
		
	}
	
	public static int buildProgram( String vertexShaderSource, String fragmentShaderSource) {
		int program;
		
		//kompilacja shaderów
		int vertexShader = compileVertexShader(vertexShaderSource);
		int fragmentShader = compileFragmentShader(fragmentShaderSource);
		
		//linkowanie w program
		program = linkProgram(vertexShader, fragmentShader);
		if(LoggerConfig.ON) {
			validateProgram(program);
		}
		
		return program;
	}
	
}
